package com.roam.mgdb;


import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Sorts;
import com.roam.DTO.SceneDetailDTO;
import com.roam.VO.TourPlanVO;
import com.roam.entity.scene.*;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.stereotype.Service;


import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
public class MongoUtils {
    private static Properties properties;
    private static MongoDatabase mongoDatabase;
    private static InputStream stream = null;
    private static String host;
    private static int port;
    private static String dbname;
    private static String username;
    private static String password;


    /*加载静态变量*/
    static {
        if (properties == null) {
            properties = new Properties();
        }

        try {
            stream = MongoUtils.class.getClassLoader().getResourceAsStream("mongodb.properties");
            properties.load(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        host = properties.getProperty("host");
        port = Integer.parseInt(properties.getProperty("port"));
        dbname = properties.getProperty("dbname");
        username = properties.getProperty("username");
        password = properties.getProperty("password");
    }

    /*定义方法，获取MongoDB连接对象*/
    public static MongoDatabase getConnect() {
        List<ServerAddress> adds = new ArrayList<>();
        //ServerAddress()两个参数分别为 服务器地址 和 端口
        System.out.println(host + port + username + dbname + password);
        ServerAddress serverAddress = new ServerAddress(host, port);
        adds.add(serverAddress);
        List<MongoCredential> credentials = new ArrayList<>();
        //MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
        MongoCredential mongoCredential = MongoCredential.createScramSha1Credential(username, dbname, password.toCharArray());
        credentials.add(mongoCredential);
        //通过连接认证获取MongoDB连接
        MongoClient mongoClient = new MongoClient(adds, credentials);
        try {
            MongoDatabase mongoDatabase = mongoClient.getDatabase("RoamTouring");
            return mongoDatabase;
        } catch (Exception e) {
            e.printStackTrace();
            return mongoDatabase;
        }

    }


    public static void findTest(String collectionName) {
        //获取数据库连接对象
        try {

            MongoDatabase mongoDatabase = getConnect();
            //根据集合（表）名获取集合
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);

            FindIterable findIterable = collection.find();
            MongoCursor cursor = findIterable.iterator();
            while (cursor.hasNext()) {
                System.out.println(cursor.next());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //该方法用于根据景点所在城市、id查询单个景点信息
    public  Scene getScene(String city, int id) {
        Scene scene = new Scene();
        try {
            MongoDatabase mongoDatabase = getConnect();
            String listName = "Attractions-" + city;
            MongoCollection<Document> collection = mongoDatabase.getCollection(listName);
            Bson bson = Filters.eq("basicInfo:id", id);
            Document doc = collection.find(bson).first();
            if (doc != null) {
                return buildScene(doc);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return scene;
    }

    //该方法用于根据景点所在城市、id查询单个景点信息
    public  TourPlanVO getSceneTourPlanVO(String city, int id) {
        TourPlanVO scene=new TourPlanVO();
        try {
            MongoDatabase mongoDatabase = getConnect();
            String listName = "Attractions-" + city;
            MongoCollection<Document> collection = mongoDatabase.getCollection(listName);
            Bson bson = Filters.eq("basicInfo:id", id);
            Document doc = collection.find(bson).first();
            if (doc != null) {
                return buildTourPlanVO(doc);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return scene;
    }


    //    该方法用于根据景点名称查询景点信息
    public static List<TourPlanVO> searchScenesByName(String sceneName) {
        List<TourPlanVO> sceneList = new ArrayList<>();
        List<Document> resultList = new ArrayList<>();
        try {
            MongoDatabase mongoDatabase = getConnect();
            MongoIterable<String> collectionNames = mongoDatabase.listCollectionNames();
            for (String collectionName : collectionNames) {
                if (!collectionName.equals("city") && collectionName.startsWith("Attractions-")) {
                    MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);
                    //使用regex操作符进行模糊匹配，正则表达式.*sceneName.*代表名字中包含sceneName的项，参数i代表不区分大小写
                    Bson bson = Filters.regex("basicInfo:name", ".*" + sceneName + ".*", "i");
                    FindIterable<Document> find = collection.find(bson);
                    for (Document document : find) {
                        resultList.add(document);
                    }
                    sceneList = docToTourPlanVOS(resultList,100);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sceneList;
    }

    //该方法用于解析文本构建Scene对象
    public static Scene buildScene(Document doc) {
        Scene scene = new Scene();
        scene.setId(doc.getInteger("basicInfo:id"));
        scene.setName(doc.getString("basicInfo:name"));
        scene.setHeat(doc.getString("basicInfo:heat"));
        scene.setScore(doc.getString("basicInfo:score"));
        scene.setPhone(doc.getString("basicInfo:phone"));
        scene.setPosition(doc.getString("basicInfo:position"));
        scene.setCity(doc.getString("basicInfo:city"));
        scene.setPrice(doc.getString("basicInfo:price") + "元/人");
        Coordinate coordinate = new Coordinate();
        coordinate.setLatitude(doc.get("basicInfo:coordinate", Document.class).get("latitude", String.class));
        coordinate.setLongitude(doc.get("basicInfo:coordinate", Document.class).get("longitude", String.class));
        scene.setCoordinate(coordinate);
        List<String> imgs = doc.get("imgs:imgs", List.class);
        if (imgs != null) {
            List<String> cleanedImgs = new ArrayList<>();
            for (String img : imgs) {
                String cleanedImg = img.substring(1, img.length() - 1); // 去掉字符串前后的圆括号
                cleanedImgs.add(cleanedImg);
            }
            scene.setImgs(cleanedImgs);
        }
        ParkDetail parkDetail = new ParkDetail();
        parkDetail.setIntroduce(doc.get("detailInfo:introduce", List.class));
        parkDetail.setOpenTime(doc.get("detailInfo:openTime", List.class));
        parkDetail.setPreferentialTreatmentPolicy(doc.get("detailInfo:preferentialTreatmentPolicy", List.class));
        parkDetail.setServiceFacilities(doc.get("detailInfo:serviceFacilities", List.class));
        scene.setDetailInfo(parkDetail);

        Nearby nearby = new Nearby();
        Document nearbyData = doc.get("nearby:nearby", Document.class);
        nearby.setNearbyAttractions(parseNearbyPlaces(nearbyData
                .get("nearbyAttractions", List.class), doc.getString("basicInfo:city")));
        nearby.setNearbyFoods(parseNearbyPlaces(nearbyData
                .get("nearbyFoods", List.class), doc.getString("basicInfo:city")));
        nearby.setNearbyShoppingMalls(parseNearbyPlaces(nearbyData
                .get("nearbyShoppingMalls", List.class), doc.getString("basicInfo:city")));
        scene.setNearby(nearby);

        scene.setPlayTime((int) Double.parseDouble(scene.getHeat()) / 3 + 1);//2

        return scene;
    }

    //该方法用于解析nearby数据
    public static List<NearbyPlace> parseNearbyPlaces(List<Document> nearbyPlacesData, String city) {
        List<NearbyPlace> nearbyPlaces = new ArrayList<>();
        for (Document placeData : nearbyPlacesData) {
            NearbyPlace place = new NearbyPlace();
            place.setImage(placeData.getString("image"));
            place.setName(placeData.getString("name"));
            place.setScore(placeData.getString("score"));
            place.setDistance(placeData.getString("distance"));
            place.setCity(city);
            place.setSceneID(getNearbyPlaceID(placeData.getString("name"), city));
            nearbyPlaces.add(place);
        }
        return nearbyPlaces;
    }

    public static int getNearbyPlaceID(String sceneName, String city) {
        Scene scene = new Scene();
        try {
            MongoDatabase mongoDatabase = getConnect();
            String listName = "Attractions-" + city;
            MongoCollection<Document> collection = mongoDatabase.getCollection(listName);
            Bson bson = Filters.eq("basicInfo:name", sceneName);
            Document doc = collection.find(bson).first();
            if (doc != null) {
                return doc.getInteger("basicInfo:id");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    //该方法用于解析文本构建TourPlanVO对象
    public static TourPlanVO buildTourPlanVO(Document doc) {
        TourPlanVO tourPlanVO = new TourPlanVO();
        tourPlanVO.setId(doc.getInteger("basicInfo:id"));
        tourPlanVO.setName(doc.getString("basicInfo:name"));
        tourPlanVO.setHeat(doc.getString("basicInfo:heat"));
        tourPlanVO.setScore(doc.getString("basicInfo:score"));
        tourPlanVO.setPosition(doc.getString("basicInfo:position"));
        tourPlanVO.setCity(doc.getString("basicInfo:city"));
        tourPlanVO.setPrice(doc.getString("basicInfo:price") + "元/人");
        List<String> imgs = doc.get("imgs:imgs", List.class);
        List<String> cleanedImgs = new ArrayList<>();
        if (imgs != null) {
            for (String img : imgs) {
                String cleanedImg = img.substring(1, img.length() - 1); // 去掉字符串前后的圆括号
                cleanedImgs.add(cleanedImg);
            }
        }
        tourPlanVO.setImg(cleanedImgs.get(0));
        tourPlanVO.setPlayTime((int) Double.parseDouble(tourPlanVO.getHeat()) / 3 + 1);
        Coordinate coordinate = new Coordinate();
        coordinate.setLatitude(doc.get("basicInfo:coordinate", Document.class).get("latitude", String.class));
        coordinate.setLongitude(doc.get("basicInfo:coordinate", Document.class).get("longitude", String.class));
        tourPlanVO.setCoordinate(coordinate);

        return tourPlanVO;
    }

    //该方法用于获取某个地点 热度 排行前n的数据....
    public List<Document> getHeatDescendingData(int amountOfData, String city) {
        return getDescendingData(amountOfData, city, "basicInfo:heat"); // 按照 heat 字段降序排序
    }

    //该方法用于获取某个地点按某项排行前n的数据
    public List<Document> getDescendingData(int amountOfData, String city, String sortBy) {
        String collectionName = "Attractions-" + city;
        List<Document> resultList = new ArrayList<>();
        //获取数据库连接对象
        try {

            MongoDatabase mongoDatabase = MongoUtils.getConnect();
            //根据集合（表）名获取集合
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);

            // 构建查询条件
            Bson sort = Sorts.descending(sortBy); // 按照 score 字段降序排序
            int skip = 0; // 不跳过，从第一条记录开始

            // 执行查询
            FindIterable<Document> result = collection.find()
                    .sort(sort)
                    .skip(skip)
                    .limit(amountOfData);
            // 将查询结果转换为列表
            for (Document document : result) {
                resultList.add(document);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }

    //该方法用于获取某个经纬度范围内的全部景点
    public static List<Document> getNearSceneByLatAndLon(String city, Double minLat, Double maxLat, Double minLong, Double maxLon, int size) {
        List<Document> resultlist = new ArrayList<>();
        String collectionName = "Attractions-" + city;
        try {
            MongoDatabase mongoDatabase = MongoUtils.getConnect();
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);


            FindIterable<Document> result = collection.find().projection(Projections.include("basicInfo:id", "basicInfo:name","basicInfo:heat","basicInfo:score",
                    "basicInfo:position","basicInfo:city","basicInfo:price","imgs:imgs","basicInfo:coordinate"));
            for (Document document : result) {
                Coordinate coordinate = new Coordinate();
                coordinate.setLongitude(document.get("basicInfo:coordinate", Document.class).get("longitude", String.class));
                coordinate.setLatitude(document.get("basicInfo:coordinate", Document.class).get("latitude", String.class));

                Double longitude = Double.parseDouble(coordinate.getLongitude());
                Double latitude = Double.parseDouble(coordinate.getLatitude());

                if(resultlist.size()>size)
                    return resultlist;
                if (longitude < maxLon && longitude > minLong && latitude < maxLat && latitude > minLat) {
                    resultlist.add(document);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultlist;
    }

    //将获得的景点文档列表转化为景点对象列表
    public static List<Scene> docToScenes(List<Document> resultList) {
        List<Scene> sceneList = new ArrayList<>();
        for (Document doc : resultList) {
            Scene scene = buildScene(doc);
            sceneList.add(scene);

            if (sceneList.size() > 25)
                break;
        }
        return sceneList;
    }

    public static List<TourPlanVO> docToTourPlanVOS(List<Document> resultList,int size) {
        List<TourPlanVO> tourPlanVOS = new ArrayList<>();
        for (Document doc : resultList) {
            TourPlanVO tourPlanVO = buildTourPlanVO(doc);
            tourPlanVOS.add(tourPlanVO);

            if (tourPlanVOS.size() > size)
                break;
        }
        return tourPlanVOS;
    }

    //根据用户选择的Scenes确定规划范围
    public static List<TourPlanVO> getNearScenes(String city, List<TourPlanVO> userChoosingScenes) {
        double minLat = Double.parseDouble(userChoosingScenes.get(0).getCoordinate().getLatitude());
        double maxLat = Double.parseDouble(userChoosingScenes.get(0).getCoordinate().getLatitude());
        double minLong = Double.parseDouble(userChoosingScenes.get(0).getCoordinate().getLongitude());
        double maxLong = Double.parseDouble(userChoosingScenes.get(0).getCoordinate().getLongitude());
        for (int i = 1; i < userChoosingScenes.size(); i++) {
            if (Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLatitude()) > maxLat)
                maxLat = Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLatitude());
            if (Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLatitude()) < minLat)
                minLat = Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLatitude());
            if (Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLongitude()) > maxLong)
                maxLong = Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLongitude());
            if (Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLongitude()) < minLong)
                minLong = Double.parseDouble(userChoosingScenes.get(i).getCoordinate().getLongitude());
        }

        if (maxLat - minLat < 0.2) {
            maxLat += 0.1;
            minLat -= 0.1;
        }
        if (maxLong - minLong < 0.2) {
            maxLong += 0.1;
            minLong -= 0.1;
        }
//        return docToScenes(getNearSceneByLatAndLon(city, minLat, maxLat, minLong, maxLong));
        int size=50;
        List<Document> doc = getNearSceneByLatAndLon(city, minLat, maxLat, minLong, maxLong,size);
        List<TourPlanVO> tourPlanVOS = docToTourPlanVOS(doc,size);

        return tourPlanVOS;
    }

    public static List<List<List<TourPlanVO>>> tourPlan(String city, List<TourPlanVO> originalUserChoosingTourPlanVOS, int days) {
        List<TourPlanVO> nearScenes = getNearScenes(city, originalUserChoosingTourPlanVOS);
        List<List<List<TourPlanVO>>> tourPlans = new ArrayList<>();

        //把Scene类的userChoosingScenes转换为TourPlanVO的userChoosingTourPlanVO
//        List<TourPlanVO> originalUserChoosingTourPlanVOS = new ArrayList<>();
//        for (TourPlanVO scene : userChoosingScenes) {
//            TourPlanVO tourPlanVO = TourPlanVO.builder()
//                    .id(scene.getId())
//                    .name(scene.getName())
//                    .heat(scene.getHeat())
//                    .score(scene.getScore())
//                    .position(scene.getPosition())
//                    .city(scene.getCity())
//                    .price(scene.getPrice())
//                    .img(scene.getImg())
//                    .playTime(scene.getPlayTime())
//                    .coordinate(scene.getCoordinate())
//                    .build();
//            originalUserChoosingTourPlanVOS.add(tourPlanVO);
//        }


        // 创建HashSet来存储userChoosingTourPlanVO中的元素
        Set<Object> set = new HashSet<>(originalUserChoosingTourPlanVOS);

        // 删除nearScenes中与userChoosingTourPlanVOS相同的元素
        nearScenes.removeIf(set::contains);

        for (int n=0;n<3;n++) {

            List<List<TourPlanVO>> tourPlan = new ArrayList<>();
            List<TourPlanVO> userChoosingTourPlanVOS=new ArrayList<>();
            for (TourPlanVO temp:originalUserChoosingTourPlanVOS) {
                userChoosingTourPlanVOS.add(temp);
            }

            for (int i = 0; i < days; i++) {
                List<TourPlanVO> dailyPlan = new ArrayList<>();
                int sumTime = 0;
                if (sumTime < 7) {
                    for (int j = 0; j < userChoosingTourPlanVOS.size(); j++) {
                        if (sumTime + userChoosingTourPlanVOS.get(j).getPlayTime() < 8) {
                            sumTime += userChoosingTourPlanVOS.get(j).getPlayTime();
                            dailyPlan.add(userChoosingTourPlanVOS.get(j));
                            userChoosingTourPlanVOS.remove(j);
                            j--;
                        }
                        if (sumTime > 7)
                            break;
                    }
                    for (int k = 0; k < nearScenes.size(); k++) {
                        if (sumTime + nearScenes.get(k).getPlayTime() < 8) {
                            sumTime += nearScenes.get(k).getPlayTime();
                            dailyPlan.add(nearScenes.get(k));
                            nearScenes.remove(k);
                            k--;
                        }
                        if (sumTime > 7)
                            break;
                    }
                }
                tourPlan.add(dailyPlan);
            }

            tourPlans.add(tourPlan);
        }
        return tourPlans;
    }
//    public static void main(String[] args) {
//        getNearSceneByLatAndLon("Attractions-上海",31.0,32.0,121.771058,127.771200);
//    }
}